Skip to content

fix: search results limit#1996

Open
alex-key wants to merge 11 commits intonpmx-dev:mainfrom
alex-key:fix/search-results-limit
Open

fix: search results limit#1996
alex-key wants to merge 11 commits intonpmx-dev:mainfrom
alex-key:fix/search-results-limit

Conversation

@alex-key
Copy link
Contributor

@alex-key alex-key commented Mar 8, 2026

🔗 Linked issue

Resolves #1923, #1921

🧭 Context

Search results pagination worked with errors for outputs with many items. There are issues with results for 1001+ items.
After investigation I've found the following limits:

  • Algolia (search endpoint) is strictly limited to 1000 hits(see jsDelivr that uses Algolia has only 100 pages of 10 items while 180k results available). See in Algolia docs. This means that we should limit our output on Algolia engine to 1000 hits. Possible solutions: use browse endpoint (see docs), but it is not available in current Algolia index used by npmx
  • npmRegistry is strictly limited to 5000 hits. After 5001 hit npm starts to return results from index 0 (does not fail or throw an error, just duplicates response). I suppose there is no workaround for that.

📚 Description

The following fixes implemented:

  • Added strict limit of 1000 results for Algolia and 5000 for npmRegistry
  • Disabled the button for the last page in pagination. Click on it starts loading of multipe queries in a row, which usually leads to HTTP 429 "Too Many Requests" and "No results" in UI
  • Added a tooltip on search results page which shown in case there are more results available
  • Fixed numbers formatting in pagination widget
  • Fixed empty state copy on search results

@vercel
Copy link

vercel bot commented Mar 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Mar 13, 2026 6:31pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Mar 13, 2026 6:31pm
npmx-lunaria Ignored Ignored Mar 13, 2026 6:31pm

Request Review

@github-actions
Copy link

github-actions bot commented Mar 8, 2026

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
i18n/locales/en.json Source changed, localizations will be marked as outdated.
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@codecov
Copy link

codecov bot commented Mar 8, 2026

Codecov Report

❌ Patch coverage is 60.46512% with 17 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/composables/npm/useSearch.ts 65.62% 10 Missing and 1 partial ⚠️
app/composables/npm/useAlgoliaSearch.ts 0.00% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2a4d9f1-7013-46a6-a6d3-24c11d230be7

📥 Commits

Reviewing files that changed from the base of the PR and between 65b6d30 and 543e481.

📒 Files selected for processing (1)
  • app/composables/npm/useAlgoliaSearch.ts

📝 Walkthrough

Walkthrough

Adds an exported SearchProvider type and new SearchResponse (extends NpmSearchResponse with totalUnlimited) in shared types; propagates totalUnlimited through search composables. Refactors useSearch: introduces SEARCH_ENGINE_HITS_LIMIT and DEFAULT_INITIAL_SEARCH_LIMIT, normalises responses, centralises cache handling, and exposes totalUnlimited in returned data. Updates useAlgoliaSearch type aliasing, generalises provider typing in several composables, removes an ARIA role from the package card keywords list, replaces a hard-coded pagination threshold with ALL_PAGES_VISIBLE_TRESHOLD and disables distant page buttons, localises displayed item numbers, and adds i18n keys/messages for “more results available”.

Possibly related PRs

Suggested labels

a11y

Suggested reviewers

  • danielroe
  • alexdln
  • knowler
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description clearly relates to the changeset, explaining the investigation of backend limits and the implemented fixes for search result pagination.
Linked Issues check ✅ Passed The pull request implements all required objectives: enforces result limits (1000 Algolia, 5000 npm), disables last-page button to prevent multi-query sequences, adds tooltips for results limit, fixes pagination number formatting, and updates empty-state messaging.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue requirements: limit enforcement, pagination controls, tooltip integration, number formatting, and search messaging updates. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.

OpenGrep is compatible with Semgrep configurations. Add an opengrep.yml or semgrep.yml configuration file to your project to enable OpenGrep analysis.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
app/components/PaginationControls.vue (1)

5-5: Rename the threshold constant before the typo spreads further.

ALL_PAGES_VISIBLE_TRESHOLD is misspelt, which makes the intent look accidental and makes future searches/reuse harder. Please rename it to ALL_PAGES_VISIBLE_THRESHOLD while it is still local to this component.

As per coding guidelines, **/*.{ts,tsx,vue} should "Use clear, descriptive variable and function names".

Also applies to: 68-68, 104-104

app/composables/useSettings.ts (1)

5-5: Prefer the shared-types auto-import here.

app/composables/* already gets shared/types/* exports auto-imported, so this extra type import is unnecessary noise.

Based on learnings, exports from shared/types/* are auto-imported by Nuxt for composables and components, so explicit imports for those types are unnecessary.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d48761f8-b319-4497-8e1e-c7c6b829a4d1

📥 Commits

Reviewing files that changed from the base of the PR and between 3712560 and 4c453dd.

📒 Files selected for processing (13)
  • app/components/Package/Card.vue
  • app/components/PaginationControls.vue
  • app/composables/npm/search-utils.ts
  • app/composables/npm/useAlgoliaSearch.ts
  • app/composables/npm/useSearch.ts
  • app/composables/npm/useUserPackages.ts
  • app/composables/useGlobalSearch.ts
  • app/composables/useSettings.ts
  • app/pages/search.vue
  • i18n/locales/en.json
  • i18n/schema.json
  • shared/types/npm-registry.ts
  • shared/types/preferences.ts
💤 Files with no reviewable changes (1)
  • app/components/Package/Card.vue

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
i18n/locales/en.json (1)

75-76: Don't bake the cap values into the English copy.

Line 76 hard-codes 1,000 and 5,000, but the real caps already live in the search logic. If those limits change again, the UI text will drift even though the behaviour is correct. Passing the caps as i18n params would keep the message aligned with enforcement.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 924a2186-bd03-4d75-93cb-6460fa8e22e2

📥 Commits

Reviewing files that changed from the base of the PR and between 4c453dd and 62b7f6e.

📒 Files selected for processing (3)
  • app/pages/search.vue
  • i18n/locales/en.json
  • i18n/schema.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • i18n/schema.json

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dfc2700e-c643-45ae-8514-6e6c703ed936

📥 Commits

Reviewing files that changed from the base of the PR and between 62b7f6e and f3e2fe6.

📒 Files selected for processing (6)
  • app/composables/npm/search-utils.ts
  • app/composables/npm/useAlgoliaSearch.ts
  • app/composables/npm/useSearch.ts
  • i18n/locales/en.json
  • i18n/schema.json
  • shared/types/npm-registry.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • i18n/locales/en.json
  • i18n/schema.json
  • shared/types/npm-registry.ts
  • app/composables/npm/useAlgoliaSearch.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/pages/search.vue (1)

455-474: Verify destructuring in watch callback behaves as intended.

The pattern watch(displayResults, ([firstResult]) => { ... }) destructures the first element from the watched array. This works because Vue's watch callback receives the new value (the array) as its first argument, and array destructuring extracts the first element.

However, this pattern may be unfamiliar to some developers. Consider adding a brief comment or using the more explicit form for clarity:

Optional: More explicit alternative
-watch(displayResults, ([firstResult]) => {
+watch(displayResults, (results) => {
+  const firstResult = results[0]
   if (!pendingEnterQuery.value) return

The current implementation is functionally correct and type-safe (thanks to optional chaining at line 470), so this is purely a readability suggestion.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1c97bcca-a9e1-4f79-9cfc-ddd40356b415

📥 Commits

Reviewing files that changed from the base of the PR and between f3e2fe6 and 65b6d30.

📒 Files selected for processing (2)
  • app/composables/npm/useSearch.ts
  • app/pages/search.vue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Search result pagination displays incorrect page count with empty pages

1 participant